// 
// SoapTrace.Net - A soap message monitoring utility. 
// 
// Copyright (C) 2004 Matthew Ward
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// 
// Matthew Ward (mrward@users.sourceforge.net)
// 

using System;
using System.Globalization;

namespace SoapTrace.Core.Communication
{
	/// <summary>
	/// A soap response message's header.
	/// </summary>
	public class SoapResponseHeader : SoapHeader
	{
		/// <summary>
		/// The Http status code of this Http header.
		/// </summary>
		private HttpStatusCode m_StatusCode = HttpStatusCode.None;

		/// <summary>
		/// The Http status codes.
		/// </summary>
		public enum HttpStatusCode : int
		{
			/// <summary>
			/// No status code specified.
			/// </summary>
			None = 0,

			/// <summary>
			/// Allows a client that is sending a request message with a request body
			///	to determine if the origin server is willing to accept the request
			/// (based on the request headers) before the client sends the request																																													  body.
			/// </summary>
			Continue = 100,

			/// <summary>
			/// The server will switch protocols to those defined by the response's
			/// Upgrade header field immediately after the empty line which
			/// terminates the 101 response.
			/// </summary>
			SwitchingProtocols =101, 

			/// <summary>
			/// The request succeeded.
			/// </summary>
			OK = 200,

			/// <summary>
			/// The request has been fulfilled and resulted in a new resource being
			/// created.
			/// </summary>
			Created = 201,

			/// <summary>
			/// The request has been accepted for processing, but the processing has
			/// not been completed. 
			/// </summary>
			Accepted = 202,

			/// <summary>
			/// The returned metainformation in the entity-header is not the
			/// definitive set as available from the origin server, but is gathered
			/// from a local or a third-party copy.
			/// </summary>
			NonAuthoritativeInformation = 203,

			/// <summary>
			/// The server has fulfilled the request but does not need to return an
			/// entity-body
			/// </summary>
			NoContent = 204,

			/// <summary>
			/// The server has fulfilled the request and the user agent SHOULD reset
			/// the document view which caused the request to be sent.
			/// </summary>
			ResetContent = 205,

			/// <summary>
			/// The server has fulfilled the partial GET request for the resource.
			/// </summary>
			PartialContent = 206,

			/// <summary>
			/// The requested resource corresponds to any one of a set of
			/// representations, each with its own specific location
			/// </summary>
			MultipleChoices = 300,

			/// <summary>
			/// The requested resource has been assigned a new permanent URI
			/// </summary>
			MovedPermanently = 301,

			/// <summary>
			/// The requested resource resides temporarily under a different URI
			/// </summary>
			Found = 302,

			/// <summary>
			/// The response to the request can be found under a different URI and
			/// SHOULD be retrieved using a GET method on that resource.
			/// </summary>
			SeeOther = 303,

			/// <summary>
			/// If the client has performed a conditional GET request and access is
			/// allowed, but the document has not been modified, the server SHOULD
			/// respond with this status code.
			/// </summary>
			NotModified = 304,

			/// <summary>
			///  The requested resource MUST be accessed through the proxy given by
			/// the Location field.
			/// </summary>
			UseProxy = 305,

			/// <summary>
			/// The requested resource resides temporarily under a different URI
			/// </summary>
			TemporaryRedirect = 307,

			/// <summary>
			/// The request could not be understood by the server due to malformed
			/// syntax
			/// </summary>
			BadRequest = 400,

			/// <summary>
			/// The request requires user authentication. 
			/// </summary>
			Unauthorized = 401,

			/// <summary>
			/// This code is reserved for future use.
			/// </summary>
			PaymentRequired = 402,

			/// <summary>
			/// The server understood the request, but is refusing to fulfill it.
			/// </summary>
			Forbidden = 403,

			/// <summary>
			///  The server has not found anything matching the Request-URI
			/// </summary>
			NotFound = 404,

			/// <summary>
			/// The method specified in the Request-Line is not allowed for the
			/// resource identified by the Request-URI.
			/// </summary>
			MethodNotAllowed = 405,

			/// <summary>
			///  The resource identified by the request is only capable of generating
			/// response entities which have content characteristics not acceptable
			/// according to the accept headers sent in the request.
			/// </summary>
			NotAcceptable = 406,  


			/// <summary>
			/// This code is similar to 401 (Unauthorized), but indicates that the
			/// client must first authenticate itself with the proxy.
			/// </summary>
			ProxyAuthenticationRequired = 407,

			/// <summary>
			/// The client did not produce a request within the time that the server
			/// was prepared to wait
			/// </summary>
			RequestTimeout = 408,

			/// <summary>
			/// The request could not be completed due to a conflict with the current
			/// state of the resource. 
			/// </summary>
			Conflict = 409,

			/// <summary>
			/// The requested resource is no longer available at the server and no
			/// forwarding address is known.
			/// </summary>
			Gone = 410,

			/// <summary>
			/// The server refuses to accept the request without a defined Content-
			/// Length. 
			/// </summary>
			LengthRequired = 411,

			/// <summary>
			/// The precondition given in one or more of the request-header fields
			/// evaluated to false when it was tested on the server. 
			/// </summary>
			PreconditionFailed = 412,

			/// <summary>
			/// The server is refusing to process a request because the request
			/// entity is larger than the server is willing or able to process.
			/// </summary>
			RequestEntityTooLarge = 413,

			/// <summary>
			/// The server is refusing to service the request because the Request-URI
			/// is longer than the server is willing to interpret. 
			/// </summary>
			RequestUriTooLarge = 414,

			/// <summary>
			///  The server is refusing to service the request because the entity of
			/// the request is in a format not supported by the requested resource
			/// for the requested method.
			/// </summary>
			UnsupportedMediaType = 415,

			/// <summary>
			///  A server SHOULD return a response with this status code if a request
			/// included a Range request-header field (section 14.35), and none of
			/// the range-specifier values in this field overlap the current extent
			/// of the selected resource, and the request did not include an If-Range
			/// request-header field.
			/// </summary>
			RequestedRangeNotSatisfiable =  416,

			/// <summary>
			/// The expectation given in an Expect request-header field 
			/// could not be met by this server
			/// </summary>
			ExpectationFailed =  417,

			/// <summary>
			/// The server encountered an unexpected condition which prevented it
			/// from fulfilling the request.
			/// </summary>
			InternalServerError = 500,

			/// <summary>
			/// The server does not support the functionality required to fulfill the
			/// request.
			/// </summary>
			NotImplemented = 501,

			/// <summary>
			/// The server, while acting as a gateway or proxy, received an invalid
			/// response from the upstream server it accessed in attempting to
			///  fulfill the request.
			/// </summary>
			BadGateway = 502,

			/// <summary>
			/// The server is currently unable to handle the request due to a
			/// temporary overloading or maintenance of the server. T
			/// </summary>
			ServiceUnavailable = 503,

			/// <summary>
			/// The server, while acting as a gateway or proxy, did not receive a
			/// timely response from the upstream server specified by the URI (e.g.
			/// HTTP, FTP, LDAP) or some other auxiliary server (e.g. DNS) it needed
			/// to access in attempting to complete the request.
			/// </summary>
			GatewayTimeout = 504,

			/// <summary>
			/// The server does not support, or refuses to support, the HTTP protocol
			/// version that was used in the request message. 
			/// </summary>
			HttpVersionNotSupported = 505,

			
			/// <summary>
			/// Extension code.  Not a status code, just an indicator that
			/// the header contains extension header fields.
			/// </summary>
			ExtensionCode = 506
		}

		/// <summary>
		/// Creates a new instance of the <see cref="SoapResponseHeader"/> class.
		/// </summary>
		public SoapResponseHeader( )
		{
		}

		/// <summary>
		/// Gets the Http status code.
		/// </summary>
		public HttpStatusCode StatusCode
		{
			get
			{
				return m_StatusCode;
			}
		}

		/// <summary>
		/// Adds a single byte to the soap response header.
		/// </summary>
		/// <param name="messageByte">A header byte.</param>
		/// <returns>A status flag indicating whether the last
		/// byte of the header was received.</returns>
		public override bool AddByte( byte messageByte )
		{
			bool HeaderReceived = base.AddByte( messageByte );

			if( HeaderReceived )
			{
				GetStatusCode( base.StartLine );

				if( m_StatusCode == HttpStatusCode.Continue )
				{
					Clear( );
					HeaderReceived = false;
					m_StatusCode = HttpStatusCode.None;
				}
			}

			return HeaderReceived;
		}

		/// <summary>
		/// Gets the Http status code for the header.
		/// </summary>
		/// <param name="startLine"></param>
		private void GetStatusCode( string startLine )
		{
			if( startLine.StartsWith( "HTTP" ) )
			{
				int SpaceIndex = startLine.IndexOf( " " );

				if( SpaceIndex != -1 )
				{
					string StatusCode = startLine.Substring( SpaceIndex );
					StatusCode = StatusCode.Trim( );

					SpaceIndex = StatusCode.IndexOf( " " );

					StatusCode = StatusCode.Substring( 0, SpaceIndex );

					int StatusCodeAsInt = Convert.ToInt32( StatusCode, CultureInfo.InvariantCulture );
					m_StatusCode = ( HttpStatusCode )StatusCodeAsInt;
				}
			}
		}
	}
}
